#ifndef __SOCKET
#define __SOCKET

#include <winsock.h>
#include <string.h>

/*
Socket.h
Underlying network communication class.
*/

class Socket
{
private:
    SOCKET m_sock;
    struct sockaddr_in m_addr;  

public:
	/*
	Constructor ++++++++++++
	Set m_sock to -1
	*/
    Socket() : m_sock(-1) {}

	/*
	Destructor +++++++++++++
	Virtual because this class should be inherited by the streams.
	*/
    virtual ~Socket() {}

	/*
	create()
	Create the socket
	returns true if socket is zero or greater
	returns false if socket is -1
	*/
    bool create()
    {
        WSADATA ws; //winsock start
        WSAStartup(0x0101, &ws); //winsock start
        m_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);   //get handle to new socket    
        if (m_sock < 0)
            return false; //return false is -1
        return true; //sock is 0 or greater
    }

	/*
	listen()
	listen to a port
	*/
    bool listen(int port)
    {
		//allocate memory for m_addr
        memset(&m_addr, 0, sizeof(m_addr));

		//set the family to AF_INET
        m_addr.sin_family = AF_INET;

		//set it to listen on all ip's
        m_addr.sin_addr.s_addr = INADDR_ANY;

		//convert the port
        m_addr.sin_port = htons(port);

		//bind to the port
        if (::bind(m_sock, (struct sockaddr *) &m_addr, sizeof(m_addr)) < 0)
            return false;
        
		//open port for listening
        if (::listen(m_sock, 0) < 0)
            return false;

        return true; //no errors
    }

	/*
	accept()
	accepts incoming connections

	pass it a pointer to a new sock
	returns ture if new sock is created.
	*/
    bool accept(Socket * new_sock)
    {
        int len = sizeof(m_addr);
        if ((new_sock->m_sock = ::accept(m_sock, (struct sockaddr *) &m_addr, &len)) < 0)
            return false;
        return true;
    }

	/*
	send()
	puts data onto the wire

	pass it the data and size
	returns the amount of data sent
	*/
    int send(char * msg, int size)
    {
        size = ::send(m_sock, msg, size, 0);
        return (size);
    }

    bool is_valid()
    {
        return m_sock!=-1;
    }

	/*
	recv()
	recieves data off the wire
	//BLOCKING

	pass a pointer to the string that will be filled
	and the size of the character string
	returns the amount of data read.
	*/
    int recv(char * msg, int buffer)
    {
        int res;
        res = ::recv(m_sock, msg, buffer, 0);
        if (res <= 0)
        {
            m_sock = -1;
            return res;
        }
        return res;
    }

	/*
	connect()

	connect to a server
	
	pass it the ip address and the port
	return false if connect fails
	*/
    bool connect(char * host, int port)
    {
        m_addr.sin_family = AF_INET;
        m_addr.sin_port = htons(port);
        m_addr.sin_addr.s_addr = inet_addr(host);

        if (::connect(m_sock, (sockaddr *) &m_addr, sizeof(m_addr)) < 0)
            return false;
        return true;      
    } 

	void shutdown()
	{
		//::shutdown(m_sock, SD_SEND);
	}
};

#endif